<?php

namespace app\api\controller;

use app\common\controller\Common;
use com\Wave;
use think\Db;

class Vad extends Common
{
    //初始文件目录
    protected $_ftp_floder = "/home/wwwroot/default/ftp/usbfile";
    //文件数组
    protected $_file = array();
    //转为mp3格式储存目录
    protected $_speech_floder = "/home/wwwroot/default/data/speech3";
    //分片保存目录
    protected $_vad_floder = "/home/wwwroot/default/data/speech4";
    //临时文件目录 没用到
    protected $_temp_floder = "/home/wwwroot/default/data/temp";
    public function __construct()
    {
        $floder = $this->_ftp_floder;
        if (!is_dir($floder)) {
            mkdir($floder);
        }
        //获取所有文件
        $files = $this->listAllFiles($floder);
        if (!$files) {
            exit;
        }
        //获取所有有效数据
        $this->_file = $this->listEffectiveFiles($files);
    }

    //开始
    public function main()
    {
        $file_list = $this->_file;
        if (!$file_list) {
            return;
        }
        foreach ($file_list as $_file_value) {
            //首先分解文件信息
            $file_arr = explode("/", $_file_value);
            if (count($file_arr) <= 9) {
                continue;
            }
            $userModel = Model('User');
            $user_name = $userModel->get($file_arr[7])->username;
            //笨方法 查看文件是否存入数据库
            $result = Db::name('none_real_speech')
                ->alias('n')
                ->join('meeting_live_speech m', 'n.lid = m.id', 'RIGHT')
                //->where(['m.filename' => $file_arr[8], 'm.did' => $file_arr[6], 'm.uid' => $file_arr[7], 'm.is_delete' => '0', 'm.is_manual' => '2'])
                ->where(['m.meeting_tag' => $user_name . '-' . $file_arr[6] . '-' . $file_arr[8], 'm.is_manual' => '2'])
                ->find();
            if (!$result) {
                //移动文件加生成波形加存入数据库
                $fileinfo = $this->moveFile($_file_value);
                if (!$fileinfo) {
                    //设备id
                    $data['did'] = $file_arr[6];
                    //用户id
                    $data['uid'] = $file_arr[7];
                    //会议id
                    $data['meeting_tag'] = $user_name . '-' . $file_arr[6] . '-' . $file_arr[8];
                    //文件名
                    $data['filename'] = $file_arr[9];
                    //格式化文件
                    $data['formatname'] = 'no file';
                    //md5
                    $data['filenamemd5'] = md5_file($_file_value);
                    //语音时长
                    $data['seconds'] = 0;
                    //开始时间结束时间
                    $data['create_time'] = $data['update_time'] = $data['start_time'] = $data['end_time'] = time();
                    //保存为手动上传状态
                    $data['is_manual'] = 2;
                    //保存异常状态
                    $data['transition_state'] = 3;
                    //保存数据库

                    //$sid = Db::name('none_real_speech')->insertGetId($data);
                    $lid = Db::name('meeting_live_speech')->insertGetId($data);
                    Db::name('none_real_speech')->insert(['lid' => $lid, 'vad' => 1]);
                    continue;
                }
                //设备id
                $data['did'] = $file_arr[6];
                //用户id
                $data['uid'] = $file_arr[7];
                //会议id
                $data['meeting_tag'] = $user_name . '-' . $file_arr[6] . '-' . $file_arr[8];
                //文件名
                $data['filename'] = $file_arr[9];
                //格式化文件
                $data['formatname'] = $fileinfo['formatname'];
                //md5
                $data['filenamemd5'] = md5_file($_file_value);
                //语音时长
                $data['seconds'] = $fileinfo['wavinfo']['seconds'] ? $fileinfo['wavinfo']['seconds'] : 0;
                //开始时间结束时间
                $data['create_time'] = $data['update_time'] = $data['start_time'] = $data['end_time'] = time();
                //保存为手动上传状态
                $data['is_manual'] = 2;
                //保存数据库

                //$sid = Db::name('none_real_speech')->insertGetId($data);
                $lid = Db::name('meeting_live_speech')->insertGetId($data);
                //分片
                $vad_arr = $this->vadFile($fileinfo['vad_path']);

                //保存分片
                foreach ($vad_arr as $key => $value) {
                    $vad_arr[$key]['sid'] = $lid;
                    $vad_arr[$key]['sorting'] = $key;
                    $vad_arr[$key]['create_time'] = $vad_arr[$key]['update_time'] = time();
                }
                Db::name('speech_vad_file')->insertAll($vad_arr);
                Db::name('none_real_speech')->insert(['lid' => $lid, 'vad' => 1]);
            } else if (!$result['formatname'] && $result['is_delete'] == 0) {
                //移动文件加生成波形加存入数据库
                $fileinfo = $this->moveFile($_file_value);
                if (!$fileinfo) {
                    continue;
                }
                //格式化文件
                $data['formatname'] = $fileinfo['formatname'];
                //语音时长
                $data['seconds'] = $fileinfo['wavinfo']['seconds'];
                //更新时间
                $data['update_time'] = time();
                //更新数据库
                Db::name('meeting_live_speech')->where('id', $result['id'])->update($data);
                //分片
                $vad_arr = $this->vadFile($fileinfo['vad_path']);
                //保存分片
                foreach ($vad_arr as $key => $value) {
                    $vad_arr[$key]['sid'] = $result['id'];
                    $vad_arr[$key]['sorting'] = $key;
                    $vad_arr[$key]['create_time'] = $vad_arr[$key]['update_time'] = time();
                }
                Db::name('speech_vad_file')->insertAll($vad_arr);
                Db::name('none_real_speech')->insert(['lid' => $result['id'], 'vad' => 1]);
            } else if (!$result['vad'] && $result['is_delete'] == 0) {
                //分片
                $vad_arr = $this->vadFile($this->_vad_floder . "/" . $result['formatname'] . ".wav");
                //保存分片
                foreach ($vad_arr as $key => $value) {
                    $vad_arr[$key]['sid'] = $result['id'];
                    $vad_arr[$key]['sorting'] = $key;
                    $vad_arr[$key]['create_time'] = $vad_arr[$key]['update_time'] = time();
                }
                Db::name('speech_vad_file')->insertAll($vad_arr);
                Db::name('none_real_speech')->where('lid', $result['id'])->update(['vad' => 1]);
            }
        }
    }

    //遍历文件夹
    function listAllFiles($from)
    {
        if (!is_dir($from))
            return false;

        $files = array();
        $dirs = array($from);
        while (NULL !== ($dir = array_pop($dirs))) {
            if ($dh = opendir($dir)) {
                while (false !== ($file = readdir($dh))) {
                    if ($file == '.' || $file == '..')
                        continue;
                    $path = $dir . '/' . $file;
                    if (is_dir($path))
                        $dirs[] = $path;
                    else
                        $files[] = $path;
                }
                closedir($dh);
            }
        }
        return $files;
    }

    //返回有效文件列表
    function listEffectiveFiles($file_list)
    {
        //判断文件列表为空
        if (!$file_list) {
            return $file_list;
        }
        $_md5s = array();
        $_files = array();
        //排序
        sort($file_list);
        //分类
        foreach ($file_list as $file_in_list) {
            if (substr($file_in_list, -3) == "md5") {
                $_md5s[] = $file_in_list;
            } else {
                $_files[] = $file_in_list;
            }
        }
        $list = array();
        //查重，保存有效文件
        while (NULL !== ($_md5 = array_pop($_md5s))) {
            while (NULL !== ($_file = array_pop($_files))) {
                if (substr($_md5, 0, -4) == substr($_file, 0, strrpos($_file, "."))) {
                    if (file_get_contents($_md5) == md5_file($_file)) {
                        $list[] = $_file;
                    }
                    break;
                }
            }
        }
        return $list;
    }

    //文件转移新文件
    public function moveFile($file)
    {
        //判断
        if (!is_file($file)) {
            return false;
        }
        //try {
        $arr_file = explode("/", $file);
        //$arr_file[7]代表用户id
        $to_dir = $this->_speech_floder . "/" . $arr_file[7];
        if (!is_dir($to_dir)) {
            @mkdir($to_dir, 0777, true);
        }
        //$temp_dir = $this->_temp_floder . "/" . $arr_file[5] . "/" . $arr_file[6] . "/" . $arr_file[7];
        $vad_dir = $this->_vad_floder;
        if (!is_dir($vad_dir)) {
            @mkdir($vad_dir, 0777, true);
        }
        //设置格式化文件名
        $formatname = trim(date('YmdHis', time()) . rand(1000, 9999));
        //判断文件格式
        $pathinfo = pathinfo($file);
        //转为wav格式来生成波形图
        switch (strtolower($pathinfo['extension'])) {
            case "pcm":
                //$cmd = "ffmpeg -f s16le -ar 16000 -ac 1 -i " . $file . " " . $temp_dir . "/" . $formatname . ".wav";
                $cmd = "ffmpeg -f s16le -ar 16000 -ac 1 -i '" . $file . "' " . $vad_dir . "/" . $formatname . ".wav";
                exec($cmd);
                break;
            case "wav":
            case "aac":
            case "m4a":
            case "amr":
            case "ogg":
            case "mp3":
                //$cmd = "ffmpeg -i " . $file . " -acodec pcm_s16le -ar 16000 -ac 1 " . $temp_dir . "/" . $formatname . ".wav"; 
                $cmd = "ffmpeg -i '" . $file . "' -acodec pcm_s16le -ar 16000 -ac 1 " . $vad_dir . "/" . $formatname . ".wav";
                exec($cmd);
                break;
            default:
                break;
        }
        //对转写的结果文件进行检查，转写正常继续，不正常则报错
        if (!is_file($vad_dir . "/" . $formatname . ".wav")) {
            return false;
        }
        //生成波形图，同时转为mp3，保存
        //$wav_to_mp3_cmd = "lame  --quiet -b 32 --resample 11 " . $temp_dir . '/' . $formatname . '.wav' . " " . $to_dir . "/" . $formatname . ".mp3";
        $wav_to_mp3_cmd = "ffmpeg -f s16le -ar 16000 -ac 1 -i '" . $vad_dir . '/' . $formatname . '.wav' . "' " . $to_dir . "/" . $formatname . ".mp3";
        @exec($wav_to_mp3_cmd);
        //$wavinfo = $this->mkjson($temp_dir . "/" . $formatname . ".wav", $to_dir . "/" . $formatname . "json");
        $wavinfo = $this->mkjson($vad_dir . "/" . $formatname . ".wav", $to_dir . "/" . $formatname . ".json");
        //} catch (\Exception $e) {
        //     echo $e->getMessage();
        //}

        return [
            'formatname' => $formatname,
            'vad_path' => $vad_dir . "/" . $formatname . ".wav",
            'wavinfo' => $wavinfo
        ];
    }

    //分片文件
    function vadFile($vadpath)
    {
        //判断文件
        if (!is_file($vadpath)) {
            return false;
        }

        $formatname = pathinfo($vadpath)['basename'];
        //将文件分片
        $vad_cmd = ("cd " . $this->_vad_floder . "; /home/wwwroot/default/data/vad_split " . $formatname);
        exec($vad_cmd);
        //判断分片文件夹
        if (!is_dir($this->_vad_floder . "/" . substr($formatname, 0, -4))) {
            //分片失败
            return false;
        }
        //获取分片文件
        $vad_test_path = $this->_vad_floder . "/" . substr($formatname, 0, -4) . "/" . "test.lst";
        $vad_arr = file($vad_test_path);
        //处理分片文件
        $return = array();
        foreach ($vad_arr as $key => $value) {
            $addr = trim(substr($value, 1));
            $time = explode("/", trim($addr))[2];
            $time_arr = explode("_", trim($time));
            $return[$key]['stime'] = $time_arr[0];
            $return[$key]['etime'] = $time_arr[1];
            $return[$key]['path'] = $this->_vad_floder . $addr . '.wav';
            $return[$key]['size'] = is_file($this->_vad_floder . $addr . '.wav') ? floor(filesize($this->_vad_floder . $addr . '.wav') / 1024) : 0;
        }
        return $return;
    }

    public function mkjson($file, $jsonfile)
    {
        $Mkmp = new Wave($file);
        $a = $Mkmp->wavechunk();
        $sample_count = ceil($a['seconds'] * $a['SamplesPerSec'] / 1000);
        $cmd = "wav2json $file  -s $sample_count -o " . "/home/wwwroot/default/test.json";
        //echo $cmd;exit;
        system($cmd);
        $ret = file_get_contents("/home/wwwroot/default/test.json");
        $data = json_decode($ret);
        foreach ($data->left as $key => $val) {
            $rt[$key] = $val;
        }
        file_put_contents($jsonfile, json_encode($rt));
        return $a;
    }
}
